package com.panopset.io;

import java.io.File;

import com.panopset.Alert;
import com.panopset.compat.Strings;
import com.panopset.UtilIO;

/**
 * Split a large text file in to manageable chunks.
 *
 * @author Karl Dinwiddie
 *
 */
public final class FileSplitter {

    /**
     * Example: java com.panopset.io.FileSplitter hugeFile.txt.
     *
     * Split is done on first return character after the split size is
     * reached.
     *
     * @param s
     *            s[0] = File name, Required. s[1] = split size in megabytes,
     *            Optional, default is 100.
     */
    public static void main(final String... s) {
        if (s == null) {
            usage();
            return;
        }
        if (s.length < 1) {
            usage();
            return;
        }
        if (!Strings.isPopulated(s[0])) {
            usage();
            return;
        }
        int mb = DEFAULT_SPLIT_SIZE;
        if (s.length > 1 && Strings.isPopulated(s[1])) {
            try {
                mb = Integer.parseInt(s[1]);
            } catch (NumberFormatException e) {
                Alert.red("Second parm not an integer: " + s[1]);
                usage();
                return;
            }
        }
        new FileSplitter(new File(s[0]), mb).run();
    }

    /**
     * File splitter.
     *
     * @param file
     *            File.
     * @param megabytes
     *            Megabytes.
     */
    public FileSplitter(final File file, final int megabytes) {
        f = file;
        m = megabytes * KILO * KILO;
    }

    /**
     * Current fileCount.
     */
    private int fileCount = 0;

    /**
     * Current byte count.
     */
    private int currentBytes = 0;

    /**
     * Locked file writer.
     */
    private LockedWriter lw;

    /**
     * @return Locked file writer.
     */
    private LockedWriter getWriter() {
        if (lw == null) {
            lw = new LockedWriter(UtilIO.combinePaths(f.getParent(),
                    f.getName() + "_" + fileCount++ + ".txt"));
        }
        return lw;
    }

    /**
     * @param s
     *            String to process.
     */
    private void proc(final String s) {
        currentBytes += s.length();
        getWriter().writeln(s);
        if (currentBytes > m) {
            reset();
        }
    }

    /**
     * Reset the writer, to prepare for the next writer.
     */
    private void reset() {
        currentBytes = 0;
        getWriter().close();
        lw = null;
    }

    /**
     * Finish processing.
     */
    private void finish() {
        reset();
    }

    /**
     * Run the File Splitter.
     */
    public void run() {
        new FileProcessor(f, new FileProcessor.Listener() {

            @Override
            public void process(final FileProcessor p, final String[] s) {
                if (s == null) {
                    return;
                }
                if (s.length < 1) {
                    return;
                }
                if (s[0] == null) {
                    return;
                }
                FileSplitter.this.proc(s[0]);
            }

            @Override
            public void finish(final FileProcessor p) {
                FileSplitter.this.finish();
            }

        }).exec();
    }

    /**
     * Print out usage.
     */
    private static void usage() {
        Alert.red("Usage:");
        Alert.red("java FileSplitter <file name> <splits, in megabytes>");
    }

    /**
     * File.
     */
    private final File f;

    /**
     * Megabytes.
     */
    private final Integer m;

    /**
     * 100.
     */
    private static final int DEFAULT_SPLIT_SIZE = 100;

    /**
     * 1024.
     */
    private static final int KILO = 1024;
}
